package com.dj.service.serviceimpl;

import ca.uhn.fhir.rest.param.StringParam;
import com.dj.bean.*;
import com.dj.constant.FhirContextContstant;
import com.dj.repository.EncounterRespository;
import com.dj.repository.JcbgHistoryRespository;
import com.dj.repository.JcbgRespository;
import com.dj.repository.PatientRespository;
import com.dj.service.JcbgService;
import org.apache.commons.collections4.CollectionUtils;
import org.hl7.fhir.dstu3.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class JcbgServiceImpl implements JcbgService {

    private static final Logger logger = LoggerFactory.getLogger(JcbgServiceImpl.class);

    @Autowired
    private JcbgRespository jcbgRespository;


    @Autowired
    private PatientRespository patientRespository;

    @Autowired
    private EncounterRespository encounterRespository;

    @Autowired
    private JcbgHistoryRespository jcbgHistoryRespository;

    @Transactional
    @Override
    public IdType saveBundle(Bundle bundle) {
        //将patient转换为json串
        String content = FhirContextContstant.getParse().encodeResourceToString(bundle);
        //获得实体对象
        JcbgBean jcbgBean = getBundleBean(bundle, content, FhirContextContstant.INITIAL_VERSION_NUMBER, null);
        //保存到库
        JcbgBean save = null;
        try {
            save = jcbgRespository.save(jcbgBean);
        } catch (Exception e) {
            logger.error("saveBundle error is {}" , e);
        }
        if (save != null) {
            String id = save.getId();
            //保存历史记录
            if (saveHistory(content, id, FhirContextContstant.INITIAL_VERSION_NUMBER)) {
                return new IdType("Bundle", id, FhirContextContstant.INITIAL_VERSION_NUMBER);
            }
        }
        return new IdType();
    }

    @Transactional
    @Override
    public IdType updateBundle(String id, String version, Bundle bundle) {
        logger.info("updateBundle version is {}, id is {}" ,version, id);
        IdType idType = new IdType();
        //判断要修改的记录是否存在，不存在直接返回空retVal
        Optional<JcbgBean> result = null;
        try {
            result = jcbgRespository.findById(id);
            logger.info("The current bundle exists in the library");
        } catch (Exception e) {
//            e.printStackTrace();
            logger.error("query error, the cause is " + e);
        }
        if (!result.isPresent()) {
            return idType;
        }

        if (version == null) {
            JcbgBean jcbgBean= result.get();
            version = jcbgBean.getVersion();
        }
        //判断要修改的记录在历史库中是否备份
        JcbgHistoryBean historyEntity = null;
        try {
            historyEntity = jcbgHistoryRespository.findByValidVersionIdAndVersion(id, version);
        } catch (Exception e) {
//            e.printStackTrace();
            logger.error("query error, the cause is ", e);
        }
        boolean saveHistory;
        if (historyEntity == null) {
            JcbgBean jcbgBean = result.get();
            saveHistory = saveHistory(jcbgBean.getContent(), jcbgBean.getId(), jcbgBean.getVersion());
        } else {
            saveHistory = true;
        }
        //判断历史存在
        if (saveHistory) {
            String content = FhirContextContstant.getParse().encodeResourceToString(bundle);
            version = String.valueOf(Long.valueOf(version) + 1L);
            JcbgBean saveBundle = getBundleBean(bundle, content, version, result.get());
            saveBundle.setId(id);
            JcbgBean save = null;
            try {
                save = jcbgRespository.save(saveBundle);
            } catch (Exception e) {
//                e.printStackTrace();
                logger.error("save error, the cause is " + e);
            }
            if (save != null) {
                if (saveHistory(content, save.getId(), version)) {
                    return new IdType("Bundle", save.getId(), save.getVersion());
                }
            }
        }
        return idType;
    }

    /**
     * 保存历史记录
     * @param content
     * @param id
     * @param version
     * @return
     */
    private boolean saveHistory(String content, String id, String version) {
        //保存历史库
        JcbgHistoryBean jcbgHistoryBean = new JcbgHistoryBean();
        jcbgHistoryBean.setValidVersionId(id);
        jcbgHistoryBean.setVersion(version);
        jcbgHistoryBean.setCreateTime(new Date());
        jcbgHistoryBean.setContent(content);
        JcbgHistoryBean saveHistory = null;
        try {
            saveHistory = jcbgHistoryRespository.save(jcbgHistoryBean);
        } catch (Exception e) {
//            e.printStackTrace();
            logger.error("save error , the cause is {}",e);
        }
        if (saveHistory != null) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Bundle getById(String id) {
        logger.info("queryById id is {}" ,id);
        Optional<JcbgBean> optional = null;
        try {
            optional = jcbgRespository.findById(id);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("query error,the cause is " + e);
        }
        if (optional.isPresent()) {
            JcbgBean jcbgBean = optional.get();
            return getBundle(jcbgBean.getContent(), jcbgBean.getId(), jcbgBean.getVersion());
        } else {
            return new Bundle();
        }
    }

    @Override
    public List<Bundle> getByItemCode(StringParam code) {
        String name = code.getValue();
        logger.info("Bundle queryByItemCode name is {}" ,name);
        //获得查询结果
        List<JcbgBean> patientEntityList = null;
        try {

            //查询检查项目的编码  code
            patientEntityList = jcbgRespository.findByItemName(name);



//            if (code.isExact()) {
//                // Do an exact match search
//                patientEntityList = jcbgRespository.findByItemName(name);
//            } else {
//                // Do a fuzzy search if possible
//                patientEntityList = jcbgRespository.findByItemNameLike(name);
//            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("query error, the cause is " + e);
        }
        return getBundleList(patientEntityList);
    }

    @Override
    public Bundle getByIdAndVersion(String id, String version) {
        logger.info("queryByIdAndVersion version is {}, id is {}" ,version, id);
        JcbgHistoryBean jcbgHistoryBean = null;
        try {
            jcbgHistoryBean = jcbgHistoryRespository.findByValidVersionIdAndVersion(id, version);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("query error, the cause is " + e);
        }
        if (jcbgHistoryBean != null) {
            return getBundle(jcbgHistoryBean.getContent(), id, version);
        } else {
            return new Bundle();
        }
    }





//    @Transactional
//    @Override
//    public Boolean deleteByBundle(Bundle bundle) {
//        Boolean retVal = false;
//        IdType theId = bundle.getIdElement();
//        String id = theId.getIdPart();
//        logger.info("deleteByBundle id is {}" ,id);
//        String version = theId.getVersionIdPart();
//        JcbgHistoryBean jcbgHistoryBean = null;
//        try {
//            jcbgHistoryBean = jcbgHistoryRespository.findByValidVersionIdAndVersion(id, version);
//        } catch (Exception e) {
//            e.printStackTrace();
//            logger.error("query error, the cause is {}" ,e.getCause());
//        }
//        boolean saveHistory;
//        if (jcbgHistoryBean == null) {
//            String content = FhirContextContstant.getParse().encodeResourceToString(bundle);
//            saveHistory = saveHistory(content, id, version);
//        } else {
//            saveHistory = true;
//        }
//        if (saveHistory) {
//            try {
//                jcbgRespository.deleteById(id);
//            } catch (Exception e) {
//                e.printStackTrace();
//                logger.error("delete error, the cause is {}" ,e.getCause());
//            }
//            retVal = true;
//        }
//        return retVal;
//    }

    /**
     * 整理bundleEntity并返回
     *
     * @param jcbgBeanList
     * @return
     */
    private List<Bundle> getBundleList(List<JcbgBean> jcbgBeanList) {
        if (CollectionUtils.isNotEmpty(jcbgBeanList)) {
            return jcbgBeanList.stream()
                    .filter(jcbgBean -> jcbgBean != null)
                    .map(jcbgBean -> getBundle(jcbgBean.getContent(), jcbgBean.getId(), jcbgBean.getVersion()))
                    .collect(Collectors.toList());
        } else {
            return Collections.emptyList();
        }
    }

    /**
     * @param content
     * @param id
     * @param version
     * @return
     */
    private Bundle getBundle(String content, String id, String version) {
        Bundle bundle = FhirContextContstant.getParse().parseResource(Bundle.class, content);
        IdType theId = new IdType("Bundle", id, version);
        bundle.setId(theId);
        bundle.setMeta(new Meta().setLastUpdated(getLastUpdatTime(id)));

        return bundle;
    }

    /**
     * @param bundle
     * @param content
     * @return
     */
    private JcbgBean getBundleBean(Bundle bundle, String content, String version, JcbgBean jcbgBean) {
        Date date = new Date();
        if (jcbgBean == null) {
            jcbgBean = new JcbgBean();
            jcbgBean.setCreateTime(date);
        }
        jcbgBean.setVersion(version);
        jcbgBean.setContent(content);
        //设置code
        String code = getCode(bundle);
        jcbgBean.setItemName(code);

        //设置更新时间
        jcbgBean.setParam1(date);
        return jcbgBean;
    }


    /**
     * 获取bundle中的检查项目编码code节点
     * @param bundle
     * @return
     */
    private String getCode(Bundle bundle) {
        List<Bundle.BundleEntryComponent> entryComponents = bundle.getEntry();
        Resource resource;
        String str = "";
        //composition.entry:Observation.code:text
        for (Bundle.BundleEntryComponent bc : entryComponents) {
            if ("observation".equals(bc.getResource().getResourceType().getPath())) {
                resource = bc.getResource();
                Property property = resource.getChildByName("code");
                Property property1 = property.getValues().get(0).getChildByName("coding");
                Base base = property1.getValues().get(0);
                List<Base> base1 = base.getChildByName("display").getValues();
                str = base1.get(0).toString();
            }
        }
        return str;
    }





    @Override
    public Boolean deleteBundle(String id) {
        Optional<JcbgBean> result = null;
        try {
            //先查询是否存在
            result = jcbgRespository.findById(id);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("Bundle query id error , the cause is {}",e.getCause());
        }

        if (result.isPresent()) {
            try {
                //记录存在 删除当前表id信息
                jcbgRespository.deleteById(id);
                logger.info("deleteBundle is success");
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("deleteBundle error , the cause is {}",e.getCause());
            }
            return true;
        } else {
            //记录不存在
            logger.error("deleteBundle error,Bundle id={} is not exist!!!", id);
            return false;
        }
    }

    @Override
    public Date getLastUpdatTime(String id) {

        Optional<JcbgBean> result = jcbgRespository.findById(id);
        if (!result.isPresent()) {
            logger.error("Bundle findById error, {} is not exist!!!", id);
            return new Date();
        }
        return result.get().getParam1();
    }

    @Override
    public Date getHistoryLastUpdatTime(String id, String version) {
        logger.info("The bundle id is {}, version is {}",id,version);
        JcbgHistoryBean jcbgHistoryBean = jcbgHistoryRespository.findByValidVersionIdAndVersion(id,version);
        if(jcbgHistoryBean!=null){
            return jcbgHistoryBean.getCreateTime();
        } else {
            return null;
        }
    }

    @Override
    public List<Bundle> getAllBundleById(String id) {
        List<JcbgHistoryBean> encounterHistoryBeans = jcbgHistoryRespository.findByValidVersionId(id);
        return geJcbgHistoryLists(encounterHistoryBeans);
    }

    @Override
    public Boolean isExist(String patientId, String encounterId) {
        logger.info("the patientId is {}, encounterId is {}",patientId,patientId);
        boolean flag = false;
        if(!patientId.isEmpty() && !encounterId.isEmpty()){
            Optional<PatientBean> patientResult = patientRespository.findById(patientId);
            if(patientResult.isPresent()){
                Optional<EncounterBean> encounterResult = encounterRespository.findById(encounterId);
                if(encounterResult.isPresent()){
                    flag = true;
                }
            }
        }
        return flag;
    }

    /**
     * 返回历史集合
     * @param jcbgHistoryBeans
     * @return
     */
    private List<Bundle> geJcbgHistoryLists(List<JcbgHistoryBean> jcbgHistoryBeans) {
        if (CollectionUtils.isNotEmpty(jcbgHistoryBeans)) {
            List<Bundle> list = jcbgHistoryBeans.stream()
                    .filter(it -> it != null)
                    .map(it -> getHistoryBundle(it.getContent(), it.getValidVersionId(), it.getVersion()))
                    .collect(Collectors.toList());

            return list;
        } else {
            logger.info("getPatientHistoryLists is empty");
            return Collections.emptyList();
        }
    }

    private Bundle getHistoryBundle(String content, String id, String version) {
        Bundle bundle = FhirContextContstant.getParse().parseResource(Bundle.class, content);
        IdType theId = new IdType("Bundle", id, version);
        bundle.setId(theId);
        bundle.setMeta(new Meta().setLastUpdated(getHistoryLastUpdatTime(id,version)));

        return bundle;
    }


}
